package com.pai4j.sso.service;
import com.pai4j.common.bean.PAIResponseBean;
import com.pai4j.common.bean.PAIResponseBeanUtil;
import com.pai4j.common.constants.WebConstant;
import com.pai4j.common.exception.AuthException;
import com.pai4j.common.util.IDGenerateUtil;
import com.pai4j.common.util.MD5Utils;
import com.pai4j.common.util.RedisUtil;
import com.pai4j.domain.vo.request.request.UserLoginInfoRequestVO;
import com.pai4j.domain.vo.request.request.UserRegistryInfoRequestVO;
import com.pai4j.domain.vo.response.UserBaseResponseVO;
import com.pai4j.remote.user.UserServiceClient;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import com.pai4j.common.enums.RedisKeyEnum;

@Service
public class SSOCoreService {

    @Autowired
    private UserServiceClient userServiceClient;

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 登录授权码兑换次数限制
     */
    private static final int MAX_EXCHANGE_COUNT = 2;

    /**
     * 账号登录服务
     *
     * @param loginInfoRequest
     * @return
     */
    public String login(UserLoginInfoRequestVO loginInfoRequest) {
        // 1. 查询账号是否存在
        UserBaseResponseVO user = this.getUserBaseInfo(loginInfoRequest.getMobile());
        Assert.notNull(user, "账号不存在！");
        // 2. 校验账号密码
        String inputPassword = MD5Utils.md5(loginInfoRequest.getPassword().concat(WebConstant.MD5_SALT));
        if (!ObjectUtils.equals(inputPassword, user.getPassword())) {
            throw new AuthException("密码错误！");
        }
        // 3. 生成登录授权码
       // return genLoginOauthCode(user.getUid());
        return null;
    }

    /**
     * 用户注册
     *
     * @param request
     * @return
     */
    // 这里其实不需要事务，因为想分享事务管理器的用法和场景，刻意添加了事务注解
    public boolean registry(UserRegistryInfoRequestVO request) {
        PAIResponseBean<Boolean> responseBean = userServiceClient.registry(request);
        if (PAIResponseBeanUtil.isOk(responseBean)) {
            return responseBean.getData();
        }
        return false;
    }

    /**
     * 判断用户是否存在
     * @param mobile
     * @return
     */
    private boolean hasUserInfo(String mobile) {
        UserBaseResponseVO userBaseResponseVO = getUserBaseInfo(mobile);
        return userBaseResponseVO != null;
    }

    private UserBaseResponseVO getUserBaseInfo(String mobile) {
        PAIResponseBean<UserBaseResponseVO> responseMessage = userServiceClient.userBaseInfo(mobile);
        if (PAIResponseBeanUtil.isOk(responseMessage)) {
            return responseMessage.getData();
        }
        throw new AuthException("用户不存在");
    }

    /**
     * 生成登录授权码
     *
     * @return
     */
    public String genLoginOauthCode(String uid) {
        // 生成登录授权码
        String oauthCode = IDGenerateUtil.uuid();
        String cacheKey = RedisKeyEnum.OAUTH_CODE_CACHE.getKey(oauthCode);
        redisUtil.set(cacheKey, uid, RedisKeyEnum.OAUTH_CODE_CACHE.getExpireTime());
        return oauthCode;
    }

    /**
     * 根据授权码获取用户ID
     *
     * @param oauthCode
     * @return
     */
    public String getUidByOauthCode(String oauthCode) {
        Long exchangeCount = this.getOauthCodeExchangeCountCache(oauthCode);
        if (exchangeCount >= MAX_EXCHANGE_COUNT) {
            throw new AuthException("授权码使用次数过多");
        }
        String cacheKey = RedisKeyEnum.OAUTH_CODE_CACHE.getKey(oauthCode);
        String uid = redisUtil.get(cacheKey);
        if (StringUtils.isNotBlank(uid)) {
            this.addExchangeCountCache(oauthCode);
            return uid;
        }
        throw new AuthException("授权码无效");
    }

    private void addExchangeCountCache(String oauthCode) {
        String cacheKey = RedisKeyEnum.OAUTH_CODE_GET_COUNT_CACHE.getKey(oauthCode);
        redisUtil.increx(cacheKey, RedisKeyEnum.OAUTH_CODE_GET_COUNT_CACHE.getExpireTime());
    }

    private Long getOauthCodeExchangeCountCache(String oauthCode) {
        String cacheKey = RedisKeyEnum.OAUTH_CODE_GET_COUNT_CACHE.getKey(oauthCode);
        String cache = redisUtil.get(cacheKey);
        return StringUtils.isBlank(cache) ? 0L : Long.valueOf(cache);
    }
}
